/*
 * Created on 21/04/2008
 * 
 */
package com.apbetioli.mapr.place.control.geocoding;

import com.apbetioli.mapr.place.dao.PlacesDao;
import com.apbetioli.mapr.place.entity.Address;
import com.apbetioli.mapr.place.entity.GeoPoint;
import com.apbetioli.mapr.place.exception.GeocodingException;
import com.apbetioli.mapr.util.SpecialCharFilter;
import com.apbetioli.mapr.util.properties.PropertiesLoaderImpl;
import com.yahoo.maps.geocode.ResultSet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;

/**
 * Yahho Maps Geocoding RestFul webservice client
 *
 * @author Alexandre Parra Betioli
 */
public class GeocoderClient {

    private static final String SCHEMA_PATH = PropertiesLoaderImpl.getValue("config.properties", "geocoder.schema");
    private static final String APPID       = PropertiesLoaderImpl.getValue("config.properties", "geocoder.appid");
    private static final String SERVICE_URL = PropertiesLoaderImpl.getValue("config.properties", "geocoder.serviceUrl");
    
    public GeoPoint transform( final Address address ) throws IOException, JAXBException, GeocodingException, UnknownHostException {

        // Mount request URL
        String request = SERVICE_URL;
        request += "?appid="   + APPID;
        
        if( (address.getStreet().trim() != null ) && (! address.getStreet().trim().equals("")) )
            request += "&street="  + SpecialCharFilter.replaceSpecial( address.getStreet().trim() );
        
        if( ! address.getCity().trim().equals("") )
            request += "&city="    + SpecialCharFilter.replaceSpecial( address.getCity().trim() );
        
        if( ! address.getState().trim().equals("") )
            request += "&state="   + SpecialCharFilter.replaceSpecial( address.getState().trim() );
        
        if( (address.getCountry() != null ) && (! address.getCountry().trim().equals("")) )
            request += "&country=" + SpecialCharFilter.replaceSpecial( address.getCountry().trim() );
            
        request = request.replaceAll(" ", "+");
        
        HttpClient client = new HttpClient();
        GetMethod  method = new GetMethod(request);
        
        // Send GET request
        int statusCode = client.executeMethod(method);
        
        if (statusCode != HttpStatus.SC_OK) {
                Logger.getLogger(PlacesDao.class.getName()).log(Level.WARNING, null, (Object[])null);
                throw new GeocodingException("Method failed: " + method.getStatusLine());
        }
        
        // Get the response body
        InputStream rstream = method.getResponseBodyAsStream();
        
        // Process the response from Yahoo! Web Services
        BufferedReader br = new BufferedReader(new InputStreamReader(rstream));
        
        StringBuffer sb = new StringBuffer();
        
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        
        br.close();
        
        // Get the result and populate GeoPoint object
        
        ResultSet rs = unmarshall( sb.toString() );
        
        GeoPoint gp = new GeoPoint();
                
        // Get the first result
        
        if( rs.getResult().size() > 0 ) {
        
            BigDecimal bdLat  = rs.getResult().get(0).getLatitude();
            BigDecimal bdLong = rs.getResult().get(0).getLongitude();
            
            gp.setLatitude( bdLat.doubleValue() );
            gp.setLongitude( bdLong.doubleValue() );
        }
        
        return gp;
    }

    private ResultSet unmarshall( final String xml ) throws JAXBException {
        
        StringReader sr = new StringReader(xml);
        BufferedReader br = new BufferedReader(sr);
        
        JAXBContext jc = JAXBContext.newInstance( SCHEMA_PATH );
        Unmarshaller u = jc.createUnmarshaller();
        
        ResultSet rs = (ResultSet) u.unmarshal(br);
        
        return rs;
    }
    
}
